home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / GDIPAL.PAK / CLIENT.C < prev    next >
C/C++ Source or Header  |  1997-05-06  |  36KB  |  1,271 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE: client.c
  9. //
  10. //  PURPOSE: Contains all input/drawing routines for the GDI Input sample.
  11. //
  12. //  FUNCTIONS:
  13. //    CreateClientWindow  - Creates the client window that handles input.
  14. //    ClientWndProc       - Processes messages for the client window.
  15. //    CmdDrawMode         - Changes the current drawing mode.
  16. //    CmdFill             - Toggles the fill mode.
  17. //    CmdCreatePen        - Puts up Pen Style dialog box.
  18. //    CmdCreateBrush      - Puts up Brush Style dialog box.
  19. //    MsgClientCreate     - Creates initial pens & brushes.
  20. //    MsgClientDestroy    - Frees owned objects.
  21. //    MsgClientKeyDown    - Looks for Escape key to cancel drawing.
  22. //    MsgClientPaint      - Paints the client window.
  23. //    MsgClientSize       - 
  24. //
  25. //    MsgClientLButtonDown
  26. //    MsgClientMouseMove => Pass mouse messages to the current handlers.
  27. //    MsgClientLButtonUp
  28. //
  29. //    PixelLBDown
  30. //    PixelMouseMove    ==> Draw individual pixels with SetPixelV.
  31. //    PixelLBUp
  32. //
  33. //    BezierLBDown
  34. //    BezierMouseMove   ==> Select 4 points for drawing a Bezier curve.
  35. //    BezierLBUp
  36. //
  37. //    RectLBDown
  38. //    RectMouseMove     ==> Select 2 points for a line, rect, or ellipse.
  39. //    RectLBUp
  40. //
  41. //    LineDraw              Given 2 points, draw a line, rect, or ellipse.
  42. //    RectDraw          ==> These functions all take identical parameters
  43. //    EllipseDraw           so they can be used interchangeably.
  44. //
  45. //    StartRubberBand     - Initiates drawing procedure.
  46. //    EndRubberBand       - Ends drawing procedure.
  47. //    ClientNewDrawing    - Erases current drawing and starts over.
  48. //
  49. //  COMMENTS:
  50. //
  51.  
  52. #include <windows.h>            // required for all Windows applications
  53. #include <windowsx.h>
  54. #include <commctrl.h>           // prototypes and defs for common controls
  55. #include "globals.h"            // prototypes specific to this application
  56. #include "toolbar.h"            // prototypes for the tool bar
  57. #include "statbar.h"            // prototypes for the status bar
  58. #include "pendlg.h"             // ID's and prototypes for the Pen dialog
  59. #include "brushdlg.h"           // ID's and prototypes for the Brush dialog
  60. #include "palette.h"            // prototypes for palette message handlers
  61.  
  62. // Global variables local to this file
  63.  
  64. HPEN    hpenBlack;              // Useful stock objects
  65. HBRUSH  hbrNull;
  66.  
  67. HPEN    hpenDraw;               // for drawing lines and frames
  68. HBRUSH  hbrReal;                // for filling interiors
  69. HBRUSH  hbrDraw;                // equals either hbrReal or hbrNull
  70.  
  71. LOGPEN  logPen;
  72. LOGBRUSH logBrush;
  73.  
  74. HDC     hdcRB;                  // DC for Rubber Banding
  75. BOOL    bDrawing;               // Flag to indicate when we are drawing
  76. UINT    uDrawMode;              // IDM_LINE, IDM_RECT, etc.
  77.  
  78. HDC     hdcBitmap;              // Used with hbmBitmap
  79. HBITMAP hbmBitmap;              // All drawing is cached here for faster screen updates
  80. UINT    cxBitmap;               // Width of bitmap
  81. UINT    cyBitmap;               // Height of bitmap
  82. HBITMAP hbmStock;               // Stock 1x1 bitmap that mem DC's are initialized with
  83.  
  84. #define BEZ_MAXPOINTS   4       // # of points in a Bezier curve
  85. POINT   pPoints[BEZ_MAXPOINTS]; // Stores coordinates for various drawing fns
  86. UINT    cPoints;                // Current # of points (for bezier)
  87.  
  88.  
  89. // The following 3 function pointers are used to point to the current
  90. // mouse handling functons.  Different drawing types can each define a
  91. // set of mouse functions.  When a new drawing mode is selected, these
  92. // pointers are set to point to the correct functions for that mode.
  93. // The main mouse message handlers then dereference these pointers to
  94. // call the correct handlers.
  95.  
  96. LRESULT  (*pfnLBDown)   (HWND, POINT);      // current mouse handler
  97. LRESULT  (*pfnLBUp)     (HWND, POINT);      // functions for rubber
  98. LRESULT  (*pfnMouseMove)(HWND, POINT);      // banding and such
  99.  
  100.  
  101. // The Line, Rectangle, and Ellipse modes use a common set of mouse
  102. // handlers that select 2 points.  The following function pointer is
  103. // used so that the correct drawing function is always used.  Like the
  104. // mouse function pointers, this is set when the drawing mode is
  105. // selected.
  106.  
  107. BOOL (*pfnDrawRect)(HDC, POINT, POINT);     // current drawing function
  108.  
  109.  
  110. // Mouse handling functions for different types of drawing.
  111. LRESULT  PixelLBDown(HWND, POINT);          // Pixels
  112. LRESULT  PixelLBUp(HWND, POINT);
  113. LRESULT  PixelMouseMove(HWND, POINT);
  114.  
  115. LRESULT  BezierLBDown(HWND, POINT);         // Bezier Curves
  116. LRESULT  BezierLBUp(HWND, POINT);
  117. LRESULT  BezierMouseMove(HWND, POINT);
  118.  
  119. LRESULT  RectLBDown(HWND, POINT);           // 2-point selection
  120. LRESULT  RectLBUp(HWND, POINT);             // Used for Lines, Rects,
  121. LRESULT  RectMouseMove(HWND, POINT);        // and Ellipses
  122.  
  123. // Generic drawing functions for use with the above Rect functions
  124. BOOL     LineDraw(HDC, POINT, POINT);
  125. BOOL     RectDraw(HDC, POINT, POINT);
  126. BOOL     EllipseDraw(HDC, POINT, POINT);
  127.  
  128.  
  129. // Other helper functions
  130. void StartRubberBand(HWND hwnd);
  131. void EndRubberBand(HWND hwnd);
  132.  
  133.  
  134. // Client window message handling functions
  135. static LRESULT MsgClientCreate      (HWND, UINT, WPARAM, LPARAM);
  136. static LRESULT MsgClientDestroy     (HWND, UINT, WPARAM, LPARAM);
  137. static LRESULT MsgClientMouseMove   (HWND, UINT, WPARAM, LPARAM);
  138. static LRESULT MsgClientLButtonDown (HWND, UINT, WPARAM, LPARAM);
  139. static LRESULT MsgClientLButtonUp   (HWND, UINT, WPARAM, LPARAM);
  140. static LRESULT MsgClientKeyDown     (HWND, UINT, WPARAM, LPARAM);
  141. static LRESULT MsgClientPaint       (HWND, UINT, WPARAM, LPARAM);
  142. static LRESULT MsgClientSize        (HWND, UINT, WPARAM, LPARAM);
  143.  
  144.  
  145. // Client window message table definitions.
  146. MSD rgmsdClient[] =
  147. {
  148.     {WM_MOUSEMOVE,       MsgClientMouseMove    },
  149.     {WM_LBUTTONDOWN,     MsgClientLButtonDown  },
  150.     {WM_LBUTTONUP,       MsgClientLButtonUp    },
  151.     {WM_KEYDOWN,         MsgClientKeyDown      },
  152.     {WM_CREATE,          MsgClientCreate       },
  153.     {WM_DESTROY,         MsgClientDestroy      },
  154.     {WM_PAINT,           MsgClientPaint        },
  155.     {WM_SIZE,            MsgClientSize         },
  156. };
  157.  
  158.  
  159. MSDI msdiClient =
  160. {
  161.     sizeof(rgmsdClient) / sizeof(MSD),
  162.     rgmsdClient,
  163.     edwpWindow
  164. };
  165.  
  166.  
  167. //
  168. //  FUNCTION: CreateClientWindow(HWND)
  169. //
  170. //  PURPOSE: Create the client window.
  171. //
  172. //  PARAMETERS:
  173. //    hwndParent - The parent (main) window.
  174. //
  175. //  RETURN VALUE:
  176. //    HWND of client window or null if failure.
  177. //
  178. //  COMMENTS:
  179. //
  180.  
  181. HWND CreateClientWindow(HWND hwndParent)
  182. {
  183.     return CreateWindowEx(0,
  184.                           "ClientWndClass",
  185.                           NULL,
  186.                           WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
  187.                           -100, -100, 10, 10,   // dummy initial coordinates
  188.                           hwndParent,
  189.                           (HMENU)-1,
  190.                           hInst,
  191.                           NULL);
  192. }
  193.  
  194.  
  195. //
  196. //  FUNCTION: ClientWndProc(HWND, UINT, WPARAM, LPARAM)
  197. //
  198. //  PURPOSE:  Processes messages for the client window.
  199. //
  200. //  PARAMETERS:
  201. //    hwnd     - window handle
  202. //    uMessage - message number
  203. //    wparam   - additional information (dependant on message number)
  204. //    lparam   - additional information (dependant on message number)
  205. //
  206. //  RETURN VALUE:
  207. //    The return value depends on the message number.  If the message
  208. //    is implemented in the message dispatch table, the return value is
  209. //    the value returned by the message handling function.  Otherwise,
  210. //    the return value is the value returned by the default window procedure.
  211. //
  212. //  COMMENTS:
  213. //    Call the DispMessage() function with the client window's message
  214. //    dispatch information (msdiClient) and the message specific information.
  215. //
  216.  
  217. LRESULT CALLBACK ClientWndProc(HWND   hwnd,
  218.                                UINT   uMessage,
  219.                                WPARAM wparam,
  220.                                LPARAM lparam)
  221. {
  222.     return DispMessage(&msdiClient, hwnd, uMessage, wparam, lparam);
  223. }
  224.  
  225.  
  226. //
  227. //  FUNCTION: CmdDrawMode(HWND, WORD, WORD, HWND)
  228. //
  229. //  PURPOSE: Handles WM_COMMAND messages to change drawing mode.
  230. //
  231. //  PARAMETERS:
  232. //    hwnd - The main window.
  233. //    wCommand - IDM_LINE, IDM_RECT, etc.
  234. //    wNotify  - Notification number (unused)
  235. //    hwndCtrl - NULL (unused)
  236. //
  237. //  RETURN VALUE:
  238. //    Always returns 0 - command handled.
  239. //
  240. //  COMMENTS:
  241. //
  242.  
  243. #pragma argsused
  244. LRESULT CmdDrawMode(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  245. {
  246.     HMENU hMenu;
  247.  
  248.     if (wCommand == uDrawMode)  // First see if the mode has changed
  249.         return 0;
  250.  
  251.     // Update the menu and toolbar states
  252.  
  253.     hMenu = GetMenu(hwnd);
  254.     CheckMenuItem(hMenu, uDrawMode, MF_BYCOMMAND|MF_UNCHECKED);
  255.     uDrawMode = wCommand;
  256.     CheckMenuItem(hMenu, uDrawMode, MF_BYCOMMAND|MF_CHECKED);
  257.  
  258.     SendMessage(hWndToolbar, TB_CHECKBUTTON, uDrawMode, MAKELONG(TRUE, 0));
  259.  
  260.     // Set the pointers for the mouse handler functions to
  261.     // the appropriate functions.
  262.  
  263.     switch(uDrawMode)
  264.     {
  265.         case IDM_PIXEL:
  266.             pfnLBDown     = PixelLBDown;
  267.             pfnLBUp       = PixelLBUp;
  268.             pfnMouseMove  = PixelMouseMove;
  269.             break;
  270.  
  271.         case IDM_BEZIER:
  272.             cPoints       = 0;
  273.             pfnLBDown     = BezierLBDown;
  274.             pfnLBUp       = BezierLBUp;
  275.             pfnMouseMove  = BezierMouseMove;
  276.             break;
  277.  
  278.         case IDM_RECT:
  279.             pfnDrawRect   = RectDraw;
  280.             pfnLBDown     = RectLBDown;
  281.             pfnLBUp       = RectLBUp;
  282.             pfnMouseMove  = RectMouseMove;
  283.             break;
  284.  
  285.         case IDM_ELLIPSE:
  286.             pfnDrawRect   = EllipseDraw;
  287.             pfnLBDown     = RectLBDown;
  288.             pfnLBUp       = RectLBUp;
  289.             pfnMouseMove  = RectMouseMove;
  290.             break;
  291.  
  292.         default:
  293.         case IDM_LINE:
  294.             pfnDrawRect   = LineDraw;
  295.             pfnLBDown     = RectLBDown;
  296.             pfnLBUp       = RectLBUp;
  297.             pfnMouseMove  = RectMouseMove;
  298.             break;
  299.     }
  300.  
  301.     return 0;
  302. }
  303.  
  304.  
  305. //
  306. //  FUNCTION: CmdFill(HWND, WORD, WORD, HWND)
  307. //
  308. //  PURPOSE: Handles the IDM_FILL and IDM_NOFILL command messages.
  309. //    Controls whether closed objects (rect's and ellipses) are filled
  310. //    with a brush when drawn.
  311. //
  312. //  PARAMETERS:
  313. //    hwnd     - The main window.
  314. //    wCommand - IDM_FILL or IDM_NOFILL
  315. //    wNotify  - Notification number (unused)
  316. //    hwndCtrl - NULL (unused)
  317. //
  318. //  RETURN VALUE:
  319. //    Always returns 0 - command handled.
  320. //
  321. //  COMMENTS:
  322. //    The toolbar has 2 buttons (IDM_FILL and IDM_NOFILL) but the
  323. //    menu only has IDM_FILL, so this function will turn filling
  324. //    OFF if wCommand is IDM_NOFILL, and TOGGLE the ON/OFF state
  325. //    if wCommand is IDM_FILL.
  326. //
  327.  
  328. #pragma argsused
  329. LRESULT CmdFill(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  330. {
  331.     static BOOL bFill;
  332.  
  333.     if (IDM_NOFILL == wCommand)
  334.         bFill = FALSE;                          // turn filling OFF
  335.     else
  336.         bFill = !bFill;                         // toggle fill state
  337.  
  338.     // Update the menu and toolbar states
  339.  
  340.     CheckMenuItem(GetMenu(hwnd),
  341.                         IDM_FILL,
  342.                   MF_BYCOMMAND | (bFill ? MF_CHECKED : MF_UNCHECKED));
  343.  
  344.     SendMessage(hWndToolbar,
  345.                 TB_CHECKBUTTON,
  346.                 (bFill ? IDM_FILL : IDM_NOFILL),
  347.                 MAKELONG(TRUE, 0));
  348.  
  349.     // Update hbrDraw and select it into the DC for drawing
  350.     hbrDraw = (bFill ? hbrReal : hbrNull);
  351.     SelectObject(hdcBitmap, hbrDraw);
  352.  
  353.      return 0;
  354. }
  355.  
  356.  
  357. //
  358. //  FUNCTION: CmdCreatePen(HWND, WORD, WORD, HWND)
  359. //
  360. //  PURPOSE: Handles the IDM_CREATEPEN command message. Puts up a dialog
  361. //    to let the user set the pen style to use for drawing.
  362. //
  363. //  PARAMETERS:
  364. //    hwnd     - The main window.
  365. //    wCommand - IDM_CREATEPEN (unused)
  366. //    wNotify  - Notification number (unused)
  367. //    hwndCtrl - NULL (unused)
  368. //
  369. //  RETURN VALUE:
  370. //    Always returns 0 - command handled.
  371. //
  372. //  COMMENTS:
  373. //
  374.  
  375. #pragma argsused
  376. LRESULT CmdCreatePen(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  377. {
  378.     LOGPEN lp = logPen;     // copy for the dialog to munge on
  379.  
  380.     if (DialogBoxParam(hInst, "PenDlg", hwnd, (DLGPROC)PenDlg, (LPARAM)&lp))
  381.     {
  382.         HPEN hpenNew = CreatePenIndirect(&lp);      // create new pen
  383.         if (!hpenNew)
  384.           {
  385.             // Should report an error here...
  386.             return 0;
  387.         }
  388.  
  389.         // Select the new pen for drawing (deselect old pen before deleting)
  390.         SelectObject(hdcBitmap, hpenNew);
  391.  
  392.         DeleteObject(hpenDraw);                     // delete old pen
  393.         hpenDraw = hpenNew;                         // save changes
  394.         logPen = lp;
  395.     }
  396.  
  397.     return 0;
  398. }
  399.  
  400.  
  401. //
  402. //  FUNCTION: CmdCreateBrush(HWND, WORD, WORD, HWND)
  403. //
  404. //  PURPOSE: Handles the IDM_CREATEBRUSH command message. Puts up a dialog
  405. //    to let the user set the brush style to use for drawing.
  406. //
  407. //  PARAMETERS:
  408. //    hwnd - The main window.
  409. //    wCommand - IDM_CREATEBRUSH (unused)
  410. //    wNotify  - Notification number (unused)
  411. //    hwndCtrl - NULL (unused)
  412. //
  413. //  RETURN VALUE:
  414. //    Always returns 0 - command handled.
  415. //
  416. //  COMMENTS:
  417. //
  418.  
  419. #pragma argsused
  420. LRESULT CmdCreateBrush(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
  421. {
  422.     LOGBRUSH lb = logBrush; // copy for the dialog to munge on
  423.  
  424.     if (DialogBoxParam(hInst, "BrushDlg", hwnd, (DLGPROC)BrushDlg, (LPARAM)&lb))
  425.     {
  426.         HBRUSH hbrNew = CreateBrushIndirect(&lb);   // create new brush
  427.         if (!hbrNew)
  428.         {
  429.             // Should report an error here...
  430.             return 0;
  431.           }
  432.  
  433.         // If "Fill Objects" is turned on, we need to update hbrDraw
  434.         if (GetMenuState(GetMenu(hwnd), IDM_FILL, MF_BYCOMMAND) & MF_CHECKED)
  435.         {
  436.             hbrDraw = hbrNew;                       // save new handle
  437.             SelectObject(hdcBitmap, hbrDraw);       // select new brush
  438.         }                                           // (deselect old brush)
  439.  
  440.         DeleteObject(hbrReal);                      // delete old brush
  441.         hbrReal = hbrNew;                           // save changes
  442.         logBrush = lb;
  443.      }
  444.  
  445.     return 0;
  446. }
  447.  
  448.  
  449. //
  450. //  FUNCTION: MsgClientCreate(HWND, UINT, WPARAM, LPARAM)
  451. //
  452. //  PURPOSE: Handles the WM_CREATE message for the client window.
  453. //
  454. //  PARAMETERS:
  455. //
  456. //    hwnd      - Window handle  (Unused)
  457. //    uMessage  - Message number (Unused)
  458. //    wparam    - Extra data     (Unused)
  459. //    lparam    - Extra data     (Unused)
  460. //
  461. //  RETURN VALUE:
  462. //
  463. //  COMMENTS:
  464. //    Initializes pens, brushes, and the off-screen bitmap.
  465. //
  466.  
  467. #pragma argsused
  468. LRESULT MsgClientCreate(HWND   hwnd,
  469.                         UINT   uMessage,
  470.                         WPARAM wparam,
  471.                         LPARAM lparam)
  472. {
  473.      HDC hdcTmp;
  474.     RECT rc;
  475.  
  476.     // Initialize pens and brushes
  477.  
  478.     hpenBlack = GetStockObject(BLACK_PEN);
  479.     hbrNull   = GetStockObject(NULL_BRUSH);
  480.  
  481.     hpenDraw  = hpenBlack;
  482.     hbrReal   = GetStockObject(GRAY_BRUSH);
  483.  
  484.     hbrDraw = hbrReal;
  485.  
  486.     GetObject(hpenDraw, sizeof(logPen), &logPen);
  487.     GetObject(hbrReal, sizeof(logBrush), &logBrush);
  488.  
  489.     // Create off-screen bitmap and DC
  490.  
  491.     hdcTmp = GetDC(hwnd);   // Screen DC for reference
  492.  
  493.     GetClientRect(hwnd, &rc);
  494.  
  495.     cxBitmap = max(rc.right, 1);
  496.     cyBitmap = max(rc.bottom, 1);
  497.      hbmBitmap = CreateCompatibleBitmap(hdcTmp, cxBitmap, cyBitmap);
  498.  
  499.     if (!hbmBitmap)
  500.     {
  501.         DeleteObject(hpenDraw);
  502.         DeleteObject(hbrReal);
  503.  
  504.         OutputDebugString("MsgClientCreate: Unable to create bitmap\r\n");
  505.         return -1;
  506.     }
  507.  
  508.     // Create memory DC to hold bitmap
  509.      hdcBitmap = CreateCompatibleDC(hdcTmp);
  510.     ReleaseDC(hwnd, hdcTmp);  // Done with this
  511.  
  512.     // Initialize memory DC
  513.     SelectObject(hdcBitmap, hpenDraw);
  514.     SelectObject(hdcBitmap, hbrDraw);
  515.     SetBkMode(hdcBitmap, TRANSPARENT);
  516.     hbmStock = SelectObject(hdcBitmap, hbmBitmap);
  517.  
  518.     if (hPalette)
  519.         SelectPalette(hdcBitmap, hPalette, FALSE);
  520.  
  521.      // Initialize bitmap to white
  522.     PatBlt(hdcBitmap, 0, 0, cxBitmap, cyBitmap, WHITENESS);
  523.  
  524.     return 0;
  525. }
  526.  
  527.  
  528. //
  529. //  FUNCTION: MsgClientDestroy(HWND, UINT, WPARAM, LPARAM)
  530. //
  531. //  PURPOSE: Handles WM_DESTROY message for the client window.
  532. //
  533. //  PARAMETERS:
  534. //
  535. //    hwnd      - Window handle  (Unused)
  536. //    uMessage  - Message number (Unused)
  537. //    wparam    - Extra data     (Unused)
  538. //    lparam    - Extra data     (Unused)
  539. //
  540. //  RETURN VALUE:
  541. //
  542. //    Always returns 0 - Message handled
  543. //
  544. //  COMMENTS:
  545. //    General clean up happens here.
  546. //
  547.  
  548. #pragma argsused
  549. LRESULT MsgClientDestroy(HWND   hwnd,
  550.                          UINT   uMessage,
  551.                          WPARAM wparam,
  552.                          LPARAM lparam)
  553. {
  554.     // Reset bitmap DC before deleting objects
  555.  
  556.      SelectObject(hdcBitmap, hpenBlack);
  557.     SelectObject(hdcBitmap, hbrNull);
  558.     SelectObject(hdcBitmap, hbmStock);
  559.  
  560.     if (hPalette)
  561.     {
  562.         SelectPalette(hdcBitmap, GetStockObject(DEFAULT_PALETTE), FALSE);
  563.         DeleteObject(hPalette);
  564.     }
  565.  
  566.     DeleteObject(hpenDraw);   // Delete pens/brushes
  567.     DeleteObject(hbrReal);
  568.  
  569.     DeleteObject(hbmBitmap);  // Delete bitmap and memory DC
  570.     DeleteDC(hdcBitmap);
  571.  
  572.     return 0;
  573. }
  574.  
  575.  
  576. //
  577. //  FUNCTION: MsgClientKeyDown(HWND, UINT, WPARAM, LPARAM)
  578. //
  579. //  PURPOSE: Handles WM_KEYDOWN message.
  580. //
  581. //  PARAMETERS:
  582. //
  583. //    hwnd      - Window handle
  584. //    uMessage  - Message number (Unused)
  585. //    wparam    - Key code (VK_xxx)
  586. //    lparam    - Extra data     (Unused)
  587. //
  588. //  RETURN VALUE:
  589. //
  590. //  COMMENTS:
  591. //    Looks for VK_ESCAPE key only.  If user hits the escape key
  592. //    while drawing, cancel the drawing operation.
  593. //
  594.  
  595. #pragma argsused
  596. LRESULT MsgClientKeyDown(HWND   hwnd,
  597.                          UINT   uMessage,
  598.                          WPARAM wparam,
  599.                          LPARAM lparam)
  600. {
  601.     if (VK_ESCAPE == wparam && bDrawing)
  602.     {
  603.         // End drawing.
  604.         EndRubberBand(hwnd);
  605.         cPoints = 0;
  606.  
  607.           // Force a repaint of the whole window to remove any junk
  608.         // left by the cancelled drawing operation.
  609.         InvalidateRect(hwnd, NULL, TRUE);
  610.     }
  611.  
  612.     return 0;
  613. }
  614.  
  615.  
  616. //
  617. //  FUNCTION: MsgClientPaint(HWND, UINT, WPARAM, LPARAM)
  618. //
  619. //  PURPOSE: Handles WM_PAINT message.
  620. //
  621. //  PARAMETERS:
  622. //
  623. //    hwnd      - Window handle
  624. //    uMessage  - Message number (Unused)
  625. //    wparam    - Extra data     (Unused)
  626. //    lparam    - Extra data     (Unused)
  627. //
  628. //  RETURN VALUE:
  629. //
  630. //  COMMENTS:
  631. //    Redraws the screen from the bitmap
  632. //
  633.  
  634. #pragma argsused
  635. LRESULT MsgClientPaint(HWND   hwnd,
  636.                        UINT   uMessage,
  637.                        WPARAM wparam,
  638.                        LPARAM lparam)
  639. {
  640.     PAINTSTRUCT ps;
  641.     HPALETTE hpalSave;
  642.  
  643.     BeginPaint(hwnd, &ps);
  644.  
  645.     if (hPalette)
  646.         hpalSave = SelectPalette(ps.hdc, hPalette, TRUE);
  647.  
  648.     BitBlt(ps.hdc,                              // Destination DC
  649.            ps.rcPaint.left,                     // Dest origin
  650.            ps.rcPaint.top,
  651.            ps.rcPaint.right - ps.rcPaint.left,  // Dest extents
  652.            ps.rcPaint.bottom - ps.rcPaint.top,
  653.            hdcBitmap,                           // Source DC
  654.            ps.rcPaint.left,                     // Source origin
  655.            ps.rcPaint.top,
  656.               SRCCOPY);                            // ROP code
  657.  
  658.     if (hPalette)
  659.         SelectPalette(ps.hdc, hpalSave, TRUE);
  660.  
  661.     EndPaint(hwnd, &ps);
  662.     return 0;
  663. }
  664.  
  665.  
  666. //
  667. //  FUNCTION: MsgClientSize(HWND, UINT, WPARAM, LPARAM)
  668. //
  669. //  PURPOSE: Handles the WM_SIZE message for the client window.
  670. //    size of the window.
  671. //
  672. //  PARAMETERS:
  673. //    hwnd - handle of Client window.
  674. //    uMessage - WM_SIZE.
  675. //    wParam - size flag (unused)
  676. //    lParam - width/height of client area (unused)
  677. //
  678. //  RETURN VALUE:
  679. //    0
  680. //
  681. //  COMMENTS:
  682. //    If the window has been enlarged, this will enlarge the bitmap to
  683. //    match the new window size.  The bitmap is never made smaller.
  684. //
  685.  
  686. #pragma argsused
  687. LRESULT MsgClientSize(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  688. {
  689.     HDC hdcTmp;
  690.     HBITMAP hbmNew;
  691.     HPALETTE hpalSave;
  692.     UINT cxNew, cyNew;
  693.     UINT cxWindow = LOWORD(lparam);
  694.     UINT cyWindow = HIWORD(lparam);
  695.  
  696.  
  697.     // First see if there's anything to do...
  698.     if (cxBitmap >= cxWindow && cyBitmap >= cyWindow)
  699.         return 0;
  700.  
  701.     // Get new bitmap dimensions
  702.     cxNew = max(cxWindow, cxBitmap);
  703.     cyNew = max(cyWindow, cyBitmap);
  704.  
  705.     // Use a screen DC to create the new bitmap so we get the
  706.     // correct color format.
  707.     hdcTmp = GetDC(hwnd);
  708.     hbmNew = CreateCompatibleBitmap(hdcTmp, cxNew, cyNew);
  709.     ReleaseDC(hwnd, hdcTmp);
  710.  
  711.     // If we couldn't create a new bitmap, just bail out now and leave
  712.      // the old bitmap intact (that's better than having nothing).
  713.     if (hbmNew == NULL)
  714.         return 0;
  715.  
  716.     // Now we need a memory DC to copy old bitmap to new one.
  717.     hdcTmp = CreateCompatibleDC(NULL);
  718.  
  719.     // Select new bitmap into permanent DC (this deselects the old bitmap)
  720.     // and then select the old bitmap into temporary DC.
  721.     SelectObject(hdcBitmap, hbmNew);
  722.     SelectObject(hdcTmp, hbmBitmap);
  723.  
  724.      if (hPalette)
  725.         hpalSave = SelectPalette(hdcTmp, hPalette, FALSE);
  726.  
  727.     // Initialize the 'extra' parts of the new bitmap with white
  728.  
  729.     if (cxWindow > cxBitmap)
  730.         PatBlt(hdcBitmap, cxBitmap, 0, cxWindow, cyWindow, WHITENESS);
  731.  
  732.     if (cyWindow > cyBitmap)
  733.         PatBlt(hdcBitmap, 0, cyBitmap, cxWindow, cyWindow, WHITENESS);
  734.  
  735.     // Copy old bitmap to new one
  736.      BitBlt(hdcBitmap,
  737.            0, 0,
  738.            cxBitmap, cyBitmap,
  739.            hdcTmp,
  740.            0, 0,
  741.            SRCCOPY);
  742.  
  743.     // Clean up
  744.     if (hPalette)
  745.         SelectPalette(hdcTmp, hpalSave, TRUE);
  746.     SelectObject(hdcTmp, hbmStock);
  747.     DeleteObject(hbmBitmap);
  748.      DeleteDC(hdcTmp);
  749.  
  750.     // Save new info
  751.     hbmBitmap = hbmNew;
  752.     cxBitmap = cxNew;
  753.     cyBitmap = cyNew;
  754.  
  755.     return 0;
  756. }
  757.  
  758.  
  759. //
  760. //  FUNCTION: MsgClientLButtonDown(HWND, UINT, WPARAM, LPARAM)
  761. //
  762. //  PURPOSE: Handles WM_LBUTTONDOWN message.
  763. //
  764. //  PARAMETERS:
  765. //
  766. //    hwnd      - Window handle
  767. //    uMessage  - Message number (Unused)
  768. //    wparam    - Extra data     (Unused)
  769. //    lparam    - Mouse coordinates
  770. //
  771. //  RETURN VALUE:
  772. //
  773. //  COMMENTS:
  774. //    Initiates dragging/drawing operation by saving the mouse
  775. //    position and capturing mouse input.
  776. //
  777.  
  778. #pragma argsused
  779. LRESULT MsgClientLButtonDown(HWND   hwnd,
  780.                              UINT   uMessage,
  781.                              WPARAM wparam,
  782.                              LPARAM lparam)
  783. {
  784.     POINT pt;
  785.  
  786.     // If we aren't already drawing, set focus to the client window
  787.     // so we can get Escape key messages should the user decide to
  788.     // quit drawing.
  789.  
  790.      if (!bDrawing)
  791.         SetFocus(hwnd);
  792.  
  793.     // Get mouse position
  794.     pt.x = (int)(short)LOWORD(lparam);
  795.     pt.y = (int)(short)HIWORD(lparam);
  796.  
  797.     // Call the current LBDown handler
  798.     return (*pfnLBDown)(hwnd, pt);
  799. }
  800.  
  801.  
  802. //
  803. //  FUNCTION: MsgClientMouseMove(HWND, UINT, WPARAM, LPARAM)
  804. //
  805. //  PURPOSE: Handles WM_MOUSEMOVE message.
  806. //
  807. //  PARAMETERS:
  808. //
  809. //    hwnd      - Window handle
  810. //    uMessage  - Message number (Unused)
  811. //    wparam    - Extra data     (Unused)
  812. //    lparam    - Mouse coordinates
  813. //
  814. //  RETURN VALUE:
  815. //
  816. //  COMMENTS:
  817. //    Performs "rubber-banding" by erasing the previous image and
  818. //    redrawing the object using an XOR ROP code.
  819. //
  820.  
  821. #pragma argsused
  822. LRESULT MsgClientMouseMove(HWND   hwnd,
  823.                            UINT   uMessage,
  824.                            WPARAM wparam,
  825.                            LPARAM lparam)
  826. {
  827.     POINT pt;
  828.     static char szBuf[20] ;     // Array for formatting mouse coordinates
  829.  
  830.      // Get new mouse position
  831.     pt.x = (int)(short)LOWORD(lparam);
  832.     pt.y = (int)(short)HIWORD(lparam);
  833.  
  834.     // Update the status bar with the new position
  835.     wsprintf(szBuf, "%d,%d", pt.x, pt.y);
  836.     UpdateStatusBar(szBuf, 2, 0);
  837.  
  838.     // Call the current MouseMove handler
  839.     return (*pfnMouseMove)(hwnd, pt);
  840. }
  841.  
  842.  
  843. //
  844. //  FUNCTION: MsgClientLButtonUp(HWND, UINT, WPARAM, LPARAM)
  845. //
  846. //  PURPOSE: Handles WM_LBUTTONUP message.
  847. //
  848. //  PARAMETERS:
  849. //
  850. //    hwnd      - Window handle
  851. //    uMessage  - Message number (Unused)
  852. //    wparam    - Extra data     (Unused)
  853. //    lparam    - Mouse coordinates
  854. //
  855. //  RETURN VALUE:
  856. //
  857. //  COMMENTS:
  858. //    Erases previous rubber-band image and draws the object in
  859. //      the final position.
  860. //
  861.  
  862. #pragma argsused
  863. LRESULT MsgClientLButtonUp(HWND   hwnd,
  864.                            UINT   uMessage,
  865.                            WPARAM wparam,
  866.                            LPARAM lparam)
  867. {
  868.     POINT pt;
  869.  
  870.     // Get new mouse position
  871.     pt.x = (int)(short)LOWORD(lparam);
  872.     pt.y = (int)(short)HIWORD(lparam);
  873.  
  874.     // Call the current LBUp handler
  875.     return (*pfnLBUp)(hwnd, pt);
  876. }
  877.  
  878.  
  879. //
  880. //  FUNCTION: xxxLBDown(HWND, UINT, WPARAM, LPARAM)
  881. //  FUNCTION: xxxMouseMove(HWND, UINT, WPARAM, LPARAM)
  882. //  FUNCTION: xxxLBUp(HWND, UINT, WPARAM, LPARAM)
  883. //
  884. //  PURPOSE: Handles WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_LBUTTONUP
  885. //
  886. //  PARAMETERS:
  887. //
  888. //    hwnd - Window handle
  889. //    pt   - Mouse coordinates
  890. //
  891. //  RETURN VALUE:
  892. //    Always return 0
  893. //
  894. //  COMMENTS:
  895. //    These functions are called by the actual Msgxxx mouse message
  896. //    handler functions (above) to perform input processing.  Three
  897. //    sets of these functions are implemented here.  One to input
  898. //    individual pixels; one to select 2 points (used to draw a
  899. //    line, rectangle, or ellipse); and one to select 4 points (for
  900. //    drawing Bezier curves).  Additional functions could be "plugged
  901. //    in" to support other types of drawing.
  902. //
  903. //    In general, xxxLBDown initializes the drawing process, for example
  904. //    by saving the initial coordinates and calling StartRubberBand;
  905. //    xxxMouseMove updates the coordinates; and xxxLBUp performs any
  906. //    final processing and clean up (EndRubberBand).
  907. //
  908.  
  909. //
  910. //  FUNCTION: PixelLBDown(HWND, UINT, WPARAM, LPARAM)
  911. //  FUNCTION: PixelMouseMove(HWND, UINT, WPARAM, LPARAM)
  912. //  FUNCTION: PixelLBUp(HWND, UINT, WPARAM, LPARAM)
  913. //
  914. //  PURPOSE: Perform single point selection (individual pixels).
  915. //
  916.  
  917. LRESULT PixelLBDown(HWND hwnd, POINT pt)
  918. {
  919.     // Get a DC and capture mouse input
  920.     StartRubberBand(hwnd);
  921.     SetROP2(hdcRB, R2_COPYPEN);
  922.  
  923.     // Draw the pixel with the current pen color into both the
  924.     // rubber-banding DC and the bitmap DC.
  925.     SetPixelV(hdcRB, pt.x, pt.y, logPen.lopnColor);
  926.     SetPixelV(hdcBitmap, pt.x, pt.y, logPen.lopnColor);
  927.  
  928.     return 0;
  929. }
  930.  
  931.  
  932. #pragma argsused
  933. LRESULT PixelMouseMove(HWND hwnd, POINT pt)
  934. {
  935.     // If we are currently drawing, draw the pixel
  936.     if (bDrawing)
  937.     {
  938.         SetPixelV(hdcRB, pt.x, pt.y, logPen.lopnColor);
  939.         SetPixelV(hdcBitmap, pt.x, pt.y, logPen.lopnColor);
  940.     }
  941.  
  942.     return 0;
  943. }
  944.  
  945.  
  946. #pragma argsused
  947. LRESULT PixelLBUp(HWND hwnd, POINT pt)
  948. {
  949.     // Don't draw the pixel again here (it's already drawn at LBDown
  950.     // and MouseMove time).  Just need to clean up.
  951.  
  952.     if (bDrawing)
  953.         EndRubberBand(hwnd);
  954.  
  955.     return 0;
  956. }
  957.  
  958.  
  959. //
  960. //  FUNCTION: BezierLBDown(HWND, UINT, WPARAM, LPARAM)
  961. //  FUNCTION: BezierMouseMove(HWND, UINT, WPARAM, LPARAM)
  962. //  FUNCTION: BezierLBUp(HWND, UINT, WPARAM, LPARAM)
  963. //
  964. //  PURPOSE: Perform 4-point selection for drawing Bezier curves.
  965. //
  966.  
  967. #pragma argsused
  968. LRESULT BezierLBDown(HWND hwnd, POINT pt)
  969. {
  970.     // If this is the first click, initialize rubber banding.
  971.  
  972.     if (0 == cPoints)
  973.         StartRubberBand(hwnd);
  974.  
  975.      return 0;
  976. }
  977.  
  978.  
  979. #pragma argsused
  980. LRESULT BezierMouseMove(HWND hwnd, POINT pt)
  981. {
  982.     int i;
  983.  
  984.     if (!bDrawing || 0 == cPoints)              // Are we currently drawing?
  985.         return 0;
  986.  
  987.     // Are we rubber banding a Bezier?
  988.     if (cPoints >= 2)
  989.         PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS); // Erase previous Bezier
  990.  
  991.     // Erase previous line segment
  992.      LineDraw(hdcRB, pPoints[cPoints - 1], pPoints[cPoints]);
  993.  
  994.     // Set the rest of the points to be the same as this one
  995.     for (i = cPoints; i < BEZ_MAXPOINTS; i++)
  996.         pPoints[i] = pt;
  997.  
  998.     // Draw new line segment
  999.     LineDraw(hdcRB, pPoints[cPoints - 1], pPoints[cPoints]);
  1000.  
  1001.     // Are we rubber banding a Bezier?
  1002.     if (cPoints >= 2)
  1003.         PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS);
  1004.  
  1005.     return 0;
  1006. }
  1007.  
  1008.  
  1009. LRESULT BezierLBUp(HWND hwnd, POINT pt)
  1010. {
  1011.     int i;
  1012.  
  1013.     if (!bDrawing)          // Are we currently drawing?
  1014.         return 0;
  1015.  
  1016.     if (cPoints >= 2)       // Are we rubber banding a Bezier?
  1017.     {
  1018.         // Erase previous Bezier
  1019.         PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS);
  1020.  
  1021.         if (cPoints == BEZ_MAXPOINTS - 1) // Is this the last point?
  1022.         {
  1023.             // If so, then erase all line segments.
  1024.             for (i = BEZ_MAXPOINTS - 1; i > 0; i--)
  1025.                 LineDraw(hdcRB, pPoints[i - 1], pPoints[i]);
  1026.         }
  1027.     }
  1028.     // else do *not* erase the previous line segments
  1029.  
  1030.     // Save new position and increment # of points
  1031.     pPoints[cPoints++] = pt;
  1032.  
  1033.     if (cPoints < BEZ_MAXPOINTS)    // Still more points to get.
  1034.     {
  1035.         // Set the rest of the points to be the same as the current one
  1036.         for (i = cPoints; i < BEZ_MAXPOINTS; i++)
  1037.             pPoints[i] = pt;
  1038.  
  1039.         // Draw new line segment
  1040.         LineDraw(hdcRB, pPoints[cPoints - 1], pPoints[cPoints]);
  1041.  
  1042.         // Once we have at least 2 points let's draw the Bezier curve
  1043.         if (cPoints >= 2)
  1044.             PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS);
  1045.     }
  1046.     else    // Finish this Bezier and quit drawing.
  1047.     {
  1048.         // Setup DC for 'real' drawing
  1049.         SetROP2(hdcRB, R2_COPYPEN);
  1050.         SetBkMode(hdcRB, TRANSPARENT);
  1051.         SelectObject(hdcRB, hpenDraw);
  1052.  
  1053.         // Draw Bezier in permanent position
  1054.         PolyBezier(hdcRB, pPoints, cPoints);
  1055.  
  1056.         // Draw it again into the bitmap DC
  1057.         PolyBezier(hdcBitmap, pPoints, cPoints);
  1058.  
  1059.         // De-select the pen and clean up rubber banding stuff.
  1060.         SelectObject(hdcRB, hpenBlack);
  1061.         EndRubberBand(hwnd);
  1062.         cPoints = 0;
  1063.     }
  1064.  
  1065.     return 0;
  1066. }
  1067.  
  1068.  
  1069. //
  1070. //  FUNCTION: RectLBDown(HWND, UINT, WPARAM, LPARAM)
  1071. //  FUNCTION: RectMouseMove(HWND, UINT, WPARAM, LPARAM)
  1072. //  FUNCTION: RectLBUp(HWND, UINT, WPARAM, LPARAM)
  1073. //
  1074. //  PURPOSE: Perform 2-point selection for drawing lines, rectangles,
  1075. //    and ellipses.
  1076. //
  1077.  
  1078. LRESULT RectLBDown(HWND hwnd, POINT pt)
  1079. {
  1080.     // Current position = starting position = mouse position
  1081.     pPoints[0] = pPoints[1] = pt;
  1082.  
  1083.     // Initialize rubber banding
  1084.     StartRubberBand(hwnd);
  1085.  
  1086.     // Draw initial state
  1087.     (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
  1088.  
  1089.     return 0;
  1090. }
  1091.  
  1092.  
  1093. #pragma argsused
  1094. LRESULT RectMouseMove(HWND hwnd, POINT pt)
  1095. {
  1096.     if (!bDrawing)          // Are we currently drawing?
  1097.         return 0;
  1098.  
  1099.     // Un-draw previous position by redrawing
  1100.     (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
  1101.  
  1102.     // Save new position
  1103.     pPoints[1] = pt;
  1104.  
  1105.     // Draw in new position
  1106.      (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
  1107.  
  1108.     return 0;
  1109. }
  1110.  
  1111.  
  1112. LRESULT RectLBUp(HWND hwnd, POINT pt)
  1113. {
  1114.     if (!bDrawing)          // Are we currently drawing?
  1115.         return 0;
  1116.  
  1117.     // Un-draw previous position by redrawing
  1118.     (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
  1119.  
  1120.     // Save new position
  1121.     pPoints[1] = pt;
  1122.  
  1123.     // Setup DC for 'real' drawing
  1124.     SetROP2(hdcRB, R2_COPYPEN);
  1125.     SetBkMode(hdcRB, TRANSPARENT);
  1126.     SelectObject(hdcRB, hpenDraw);
  1127.     SelectObject(hdcRB, hbrDraw);
  1128.  
  1129.     // Draw object in permanent position
  1130.     (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
  1131.  
  1132.     // Draw it again into the bitmap DC
  1133.     (*pfnDrawRect)(hdcBitmap, pPoints[0], pPoints[1]);
  1134.  
  1135.     // De-select the pen and brush by selecting stock objects
  1136.     // and clean up rubber banding stuff.
  1137.     SelectObject(hdcRB, hpenBlack);
  1138.     SelectObject(hdcRB, hbrNull);
  1139.     EndRubberBand(hwnd);
  1140.  
  1141.     return 0;
  1142. }
  1143.  
  1144.  
  1145. //
  1146. //  FUNCTION: xxxxDraw(HDC hdc, POINT pt1, POINT pt2)
  1147. //
  1148. //  PURPOSE: Draws a Line, Rectangle, or Ellipse at the coordinates
  1149. //    given by pt1 and pt2.
  1150. //
  1151. //  PARAMETERS:
  1152. //    hdc   - Device context to draw into.
  1153. //    pt1   - Beginning point (upper-left corner of rect)
  1154. //    pt2   - Ending point    (lower-right corner of rect)
  1155. //
  1156. //  RETURN VALUE:
  1157. //    TRUE for success, FALSE otherwise.
  1158. //
  1159. //  COMMENTS:
  1160. //    Assumes the DC is already correctly set up.
  1161. //
  1162. //
  1163.  
  1164. BOOL LineDraw(HDC hdc, POINT pt1, POINT pt2)
  1165. {
  1166.     MoveToEx(hdc, pt1.x, pt1.y, NULL);
  1167.     return LineTo(hdc, pt2.x, pt2.y);
  1168. }
  1169.  
  1170.  
  1171. BOOL RectDraw(HDC hdc, POINT pt1, POINT pt2)
  1172. {
  1173.     return Rectangle(hdc, pt1.x, pt1.y, pt2.x, pt2.y);
  1174. }
  1175.  
  1176.  
  1177. BOOL EllipseDraw(HDC hdc, POINT pt1, POINT pt2)
  1178. {
  1179.     return Ellipse(hdc, pt1.x, pt1.y, pt2.x, pt2.y);
  1180. }
  1181.  
  1182.  
  1183. //
  1184. //  FUNCTION: StartRubberBand(HWND)
  1185. //
  1186. //  PURPOSE: Sets up DC for rubber banding and captures the mouse.
  1187. //
  1188. //  PARAMETERS:
  1189. //    hwnd - Window for GetDC
  1190. //
  1191. //  RETURN VALUE:
  1192. //    None
  1193. //
  1194. //  COMMENTS:
  1195. //
  1196.  
  1197. void StartRubberBand(HWND hwnd)
  1198. {
  1199.     hdcRB = GetDC(hwnd);                        // Get a DC to draw to
  1200.  
  1201.     // select our logical palette so palette-relative colors work correctly
  1202.     if (hPalette)
  1203.         SelectPalette(hdcRB, hPalette, TRUE);
  1204.  
  1205.     // R2_NOT causes drawing with a pen to invert the screen pixels.
  1206.     // This makes it easy to erase something by drawing it a 2nd time.
  1207.     SetROP2(hdcRB, R2_NOT);
  1208.  
  1209.     // For rubber banding with R2_NOT, we use a single pixel pen and
  1210.     // a NULL brush.
  1211.     SelectObject(hdcRB, hpenBlack);
  1212.     SelectObject(hdcRB, hbrNull);
  1213.  
  1214.     SetCapture(hwnd);                           // Capture mouse input
  1215.     bDrawing = TRUE;
  1216. }
  1217.  
  1218.  
  1219. //
  1220. //  FUNCTION: EndRubberBand(HWND)
  1221. //
  1222. //  PURPOSE: Releases rubber banding DC and mouse capture.
  1223. //
  1224. //  PARAMETERS:
  1225. //    hwnd - Window for ReleaseDC
  1226. //
  1227. //  RETURN VALUE:
  1228. //    None
  1229. //
  1230. //  COMMENTS:
  1231. //
  1232.  
  1233. void EndRubberBand(HWND hwnd)
  1234. {
  1235.     // de-select our logical palette from the DC
  1236.     if (hPalette)
  1237.         SelectPalette(hdcRB, GetStockObject(DEFAULT_PALETTE), TRUE);
  1238.  
  1239.     ReleaseDC(hwnd, hdcRB);
  1240.     ReleaseCapture();
  1241.     bDrawing = FALSE;
  1242. }
  1243.  
  1244.  
  1245. //
  1246. //  FUNCTION: ClientNewDrawing(VOID)
  1247. //
  1248. //  PURPOSE: Erase drawing and start over
  1249. //
  1250. //  PARAMETERS:
  1251. //    None
  1252. //
  1253. //  RETURN VALUE:
  1254. //    None
  1255. //
  1256. //  COMMENTS:
  1257. //
  1258.  
  1259. VOID ClientNewDrawing(VOID)
  1260. {
  1261.     if (hWndClient && hdcBitmap)
  1262.     {
  1263.         HCURSOR hcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1264.  
  1265.         PatBlt(hdcBitmap, 0, 0, cxBitmap, cyBitmap, WHITENESS);
  1266.         InvalidateRect(hWndClient, NULL, TRUE);
  1267.  
  1268.         SetCursor(hcurSave);
  1269.     }
  1270. }
  1271.